#
# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
#

"""异常构造函数发射器

处理异常类型的构造调用，为 mc::exception 类型生成特殊的构造代码。
"""

from typing import Any
from mcpy.ir.expressions import IRCall, IRConstant
from mcpy.ir.expressions.string import IRSFormat
from mcpy.codegen.core.context import CodeGenContext
from mcpy.codegen.core.emitter import NodeTypeEmitter, EmitResult
from mcpy.codegen.configs.operators import get_operator_precedence
from mcpy.symbol_meta import SymbolKind
from ..core.generator import get_global_generator


def is_exception_type(symbol: Any, context: CodeGenContext) -> bool:
    """检查符号是否是异常类型

    通过检查继承链判断，只有继承自 Exception 或 BaseException 的类型才是异常类型
    """
    if not symbol.type_config:
        return False

    # 检查 cpp_type 是否直接是 mc::exception
    cpp_type = symbol.type_config.get("cpp_type", "")
    if cpp_type == "mc::exception":
        return True

    # 检查 inherit_from 字段
    inherit_from = symbol.type_config.get("inherit_from")
    if inherit_from:
        if inherit_from in ("Exception", "BaseException"):
            return True
        # 递归检查父类
        if context.current_node:
            parent_symbol = context.current_node.lookup_symbol(inherit_from)
            if parent_symbol and is_exception_type(parent_symbol, context):
                return True

    # 检查 base_classes 字段（向后兼容）
    base_classes = symbol.type_config.get("base_classes", [])
    for base_class in base_classes:
        if base_class in ("Exception", "BaseException"):
            return True
        # 递归检查基类
        if context.current_node:
            base_symbol = context.current_node.lookup_symbol(base_class)
            if base_symbol and is_exception_type(base_symbol, context):
                return True

    return False


def is_mc_exception_type(symbol: Any, context: CodeGenContext) -> bool:
    """检查异常类型是否继承自 mc::exception

    通过检查继承链判断，Python 的 Exception 映射到 mc::exception
    """
    if not symbol.type_config:
        return False

    # 检查 cpp_type 是否等于 mc::exception
    cpp_type = symbol.type_config.get("cpp_type", "")
    if cpp_type == "mc::exception":
        return True

    # 检查 inherit_from 字段
    inherit_from = symbol.type_config.get("inherit_from")
    if inherit_from:
        if inherit_from == "Exception":
            # Exception 映射到 mc::exception
            return True
        # 递归检查父类
        if context.current_node:
            parent_symbol = context.current_node.lookup_symbol(inherit_from)
            if parent_symbol and is_mc_exception_type(parent_symbol, context):
                return True

    # 检查 base_classes 字段（向后兼容）
    base_classes = symbol.type_config.get("base_classes", [])
    for base_class in base_classes:
        if base_class == "Exception":
            # Exception 映射到 mc::exception
            return True
        if context.current_node:
            base_symbol = context.current_node.lookup_symbol(base_class)
            if base_symbol and is_mc_exception_type(base_symbol, context):
                return True

    return False


class ExceptionConstructorEmitter(NodeTypeEmitter):
    """处理异常类型构造函数的发射器

    将异常类型的构造调用转换为特殊的代码：
    - mc::exception 类型：使用 MC_MAKE_EXCEPTION 宏
    - 标准异常：使用普通构造函数

    示例：
    - ValueError("error") → MC_MAKE_EXCEPTION(mcpy::value_error, "error")
    - NotImplementedError(f"{type} error") → MC_MAKE_EXCEPTION(mcpy::not_implemented_error, "...")
    - std::runtime_error("error") → std::runtime_error("error")
    """

    def __init__(self):
        super().__init__([IRCall])

    def emit(self, node: IRCall, context: CodeGenContext) -> EmitResult | None:
        """生成异常构造代码

        只处理异常类型的构造调用，其他调用返回 None 让其他发射器处理。
        """
        # 获取函数名
        func_name = node.get_func_name()
        if not func_name:
            return None

        # 查找符号，检查是否是异常类型
        if not context.current_node:
            return None

        symbol = context.current_node.lookup_symbol(func_name)
        if not symbol or symbol.kind != SymbolKind.CLASS:
            return None

        # 检查是否是异常类型（通过 type_config 判断）
        if not symbol.type_config:
            return None

        # 判断是否是异常类型（基类包含 Exception 或 BaseException）
        if not is_exception_type(symbol, context):
            return None

        # 获取 C++ 类型
        cpp_type = symbol.type_config.get("cpp_type")
        if not cpp_type:
            return None

        # 添加必要的头文件
        includes = symbol.type_config.get("includes", [])
        for include in includes:
            context.require_include(include)

        # 检查是否是 mc::exception 类型
        is_mc_exception = is_mc_exception_type(symbol, context)

        if is_mc_exception:
            # mc::exception 类型：使用 MC_MAKE_EXCEPTION
            return self._emit_mc_exception_constructor(cpp_type, node, context)
        else:
            # 标准异常：使用普通构造
            return self._emit_standard_exception_constructor(cpp_type, node, context)

    def _emit_mc_exception_constructor(
        self, cpp_type: str, node: IRCall, context: CodeGenContext
    ) -> EmitResult:
        """生成 mc::exception 类型的构造代码

        使用 MC_MAKE_EXCEPTION 宏或默认构造：
        - 无参数：exception_type() （使用默认构造函数）
        - 单参数字符串：MC_MAKE_EXCEPTION(exception_type, "message")
        - 单参数 f-string：MC_MAKE_EXCEPTION(exception_type, "format", args...)
        - 单参数表达式：MC_MAKE_EXCEPTION(exception_type, "{}", expr)
        - 多参数：exception_type(mc::variants{...})
        """
        context.require_include("mcpy/exception.h")
        generator = get_global_generator()

        # 无参数：使用默认构造函数（MC_MAKE_EXCEPTION 不支持无参数）
        if not node.args:
            code = f"{cpp_type}()"
            return EmitResult(code=code, precedence=get_operator_precedence("call"))

        # 单参数
        if len(node.args) == 1:
            arg = node.args[0]

            # f-string
            if isinstance(arg, IRSFormat):
                code = self._generate_exception_from_fstring(cpp_type, arg, context)
            # 字面量字符串
            elif isinstance(arg, IRConstant) and isinstance(arg.value, str):
                code = self._generate_exception_from_literal(cpp_type, arg.value)
            # 运行时表达式
            else:
                arg_code = generator.generate_expression(arg, context)
                code = f'MC_MAKE_EXCEPTION({cpp_type}, "{{}}", ({arg_code}))'

            return EmitResult(code=code, precedence=get_operator_precedence("call"))

        # 多参数 - 使用 mc::variants
        args_codes = [
            f"mc::variant({generator.generate_expression(arg, context)})"
            for arg in node.args
        ]
        args_list = ", ".join(args_codes)
        code = f"{cpp_type}(mc::variants{{{args_list}}})"

        return EmitResult(code=code, precedence=get_operator_precedence("call"))

    def _emit_standard_exception_constructor(
        self, cpp_type: str, node: IRCall, context: CodeGenContext
    ) -> EmitResult:
        """生成标准异常（非 mc::exception）的构造代码"""
        generator = get_global_generator()
        args_codes = [generator.generate_expression(arg, context) for arg in node.args]
        args_str = ", ".join(args_codes) if args_codes else ""
        code = f"{cpp_type}({args_str})"

        return EmitResult(code=code, precedence=get_operator_precedence("call"))

    def _generate_exception_from_literal(
        self, exception_type: str, literal_str: str
    ) -> str:
        """从字面量字符串生成 MC_MAKE_EXCEPTION 代码"""
        # 检查是否包含占位符
        if "{" in literal_str or "$" in literal_str:
            # 转义占位符
            escaped = literal_str.replace("{", "{{").replace("}", "}}")
            escaped = escaped.replace("$", "$$")
        else:
            escaped = literal_str

        # 转义 C++ 字符串中的特殊字符
        escaped = escaped.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")

        return f'MC_MAKE_EXCEPTION({exception_type}, "{escaped}")'

    def _generate_exception_from_fstring(
        self, exception_type: str, format_node, context: CodeGenContext
    ) -> str:
        """将 f-string 转换为 MC_MAKE_EXCEPTION 调用

        将 Python f-string 格式 {} 转换为 libmcpp 格式

        IRSFormat 有以下属性：
        - format_str: 格式字符串，其中 {} 是占位符
        - named_args: [(name, value_node), ...] 参数列表
        """
        generator = get_global_generator()

        # 获取格式字符串（已经有 {} 占位符）
        format_str = format_node.format_str

        # 转义 C++ 字符串中的特殊字符
        format_str = (
            format_str.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
        )

        # MC_MAKE_EXCEPTION 使用 {} 格式占位符（与 Python f-string 相同）
        # 所以不需要转换，保持 {} 即可

        # 生成参数代码
        args = []
        for _, value_node in format_node.named_args:
            arg_code = generator.generate_expression(value_node, context)
            args.append(f"({arg_code})")

        if args:
            # 使用链式调用格式：(arg1)(arg2)(arg3)
            args_str = "".join(args)
            return f'MC_MAKE_EXCEPTION({exception_type}, "{format_str}", {args_str})'
        else:
            return f'MC_MAKE_EXCEPTION({exception_type}, "{format_str}")'

    def get_priority(self) -> int:
        """获取发射器优先级

        异常构造比普通类型构造更特殊，需要更高的优先级
        TypeConstructorEmitter 的优先级是 55
        """
        return 60  # 比 TypeConstructorEmitter(55) 更高
